/*
 * rltime.c
 *
 *  Created on: 2023年11月23日
 *      Author: hello
 */


#include "rltime.h"
#include <stdlib.h>
#include <stdio.h>

/*
 * 一个自然周期为4年，包含3个平年一个闰年
 */
#define CYCLE_DAYS    (1461U)                       /* (365 * 4 + 1)                */
#define CYCLE_HOURS   (35064U)                      /* (365 * 4 + 1) * 24           */
#define CYCLE_MINUTES (2103840U)                    /* (365 * 4 + 1) * 24 * 60      */
#define CYCLE_SECPNDS (126230400U)                  /* (365 * 4 + 1) * 24 * 60 * 60 */

#define TIMEZONE      (28800UL)                      /* 8个小时的秒数。东八区快8个小时，东正西负   */


/**
 * 根据传入的日期计算星期几，返回值范围0~6,0表示星期天
 */
uint8_t rl_weekday(uint32_t year, uint8_t month, uint8_t day)
{
    uint32_t weekday = 0U;
    if(month < 3U)
    {
        /*D = { [(23 x month)/9] + day + 4 + year + [(year-1)/4] - [(year-1)/100] + [(year-1)/400] } mod 7*/
        weekday = (((23U * month) / 9U) + day + 4U + year
                   + ((year - 1U) / 4U) - ((year - 1U) / 100U)
                   + ((year - 1U) / 400U)) % 7U;
    }
    else
    {
        /*D = { [(23 x month)/9] + day + 4 + year + [year/4] - [year/100] + [year/400] - 2 } mod 7*/
        weekday = (((23U * month) / 9U) + day + 4U + year + (year / 4U)
                   - (year / 100U) + (year / 400U) - 2U) % 7U;
    }
    return (uint8_t) weekday;
}

/**
 * 判断是否是闰年
 */
int rl_isleap(int year)
{
	if (year % 400 == 0)
		return 1;
	if (year % 100 == 0)
		return 0;
	return (year % 4 == 0);
}

/**
 * 将rl_time_t转为时间戳
 */
uint32_t rl_timeunpack(const rl_time_t* t)
{
	uint32_t i = 0, days = 0, timestamp = 0;
    uint8_t mdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	for(i = 1970; i < t->year; i++)
	{
		if(rl_isleap(i))  /* 判断是否是闰年 */
			days += 366;
		else
			days += 365;
	}
    if(rl_isleap(i))  /* 判断是否是闰年 */
    	mdays[1] = 29;
	for(i = 0; i < t->mon - 1; i++)
		days += mdays[i];
	days += (t->mday - 1);
	timestamp = days * 24 * 60 * 60;
	timestamp += t->hour * 60 * 60;
	timestamp += t->min * 60;
	timestamp += t->sec;
	return timestamp;
}

/**
 * 将时间戳转为rl_time_t结构
 */
void rl_timepack(uint32_t timestamp, rl_time_t* t)
{
    uint32_t year, mon, mday, hour, min, sec, yday, wday, dayOfCycle, i, cycle, day = 0;
    uint8_t days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    sec = timestamp % 60; /* 秒 */
    timestamp /= 60;
    min = timestamp % 60; /* 分 */
    timestamp /= 60;
    hour = timestamp % 24; /* 时 */
    timestamp /= 24;
    cycle = timestamp / CYCLE_DAYS; /* 自1970年到现在已经过去的周期数（一个周期为4年） */
    dayOfCycle = timestamp % CYCLE_DAYS; /* 本周期内已过的天数 */
    if(dayOfCycle < 365)  /* 周期内的第一年为平年 */
    {
        year = 1970 + cycle * 4; /* 年 */
        yday = dayOfCycle + 1; /* 本年度的第几天 */
    }
    else if(dayOfCycle >= 365 && dayOfCycle < 730)  /* 周期内的第二年为平年 */
    {
        year = 1970 + cycle * 4 + 1;
        yday = dayOfCycle - 365 + 1;
    }
    else if(dayOfCycle >= 730 && dayOfCycle < 1096)  /* 周期内的第三年为闰年 */
    {
        year = 1970 + cycle * 4 + 2;
        yday = dayOfCycle - 730 + 1;
    }
    else /* 周期内的第四年为平年 */
    {
        year = 1970 + cycle * 4 + 3;
        yday = dayOfCycle - 1096 + 1;
    }
    /* 闰年的二月是29天 */
    if(rl_isleap(year)) days[1] = 29;
    for(i = 0; i < 12; i++)
    {
        day += days[i];
        if(day >= yday)
        {
            mon = i + 1; /* 月 */
            mday = days[i] - (day - yday); /* 日 */
            break;
        }
    }
    wday = rl_weekday(year, mon, mday); /* 周几 */
	t->year = year;
	t->mon  = mon;
	t->mday = mday;
	t->hour = hour;
	t->min  = min;
	t->sec  = sec;
	t->wday = wday;
	t->yday = yday;
}

/**
 * 格式化输出时间字符串
 */
void rl_timestring(const rl_time_t *t, char* buf, uint32_t bufsize)
{
	static const char* wday[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
	snprintf(buf, bufsize, "%04d/%02d/%02d %02d:%02d:%02d %s",
			t->year,
			t->mon,
			t->mday,
			t->hour,
			t->min,
			t->sec,
			wday[t->wday]);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// 移植接口
///
///

#include <time.h>

uint32_t rl_time(uint32_t* timestamp)
{
	uint32_t ts = 0;
	ts = time((time_t *)timestamp);
	return ts;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// 使用示例
///
///

#if 0

#include "rltime.h"
#include <stdio.h>
#include <stdlib.h>

int main()
{
	uint32_t timestamp;
	rl_time_t ts;
	char buf[64];

	timestamp = rl_time(NULL);
	printf("utc time:%d \n", timestamp);

	timestamp += (60 * 60 * 8);
	printf("local time:%d \n", timestamp);

	rl_timepack(timestamp, &ts);

	rl_timestring(&ts, buf, sizeof(buf));
	printf("%s\n", buf);

	return 0;
}

#endif
